package com.example.ipcdemo.aidl;

import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.example.ipcdemo.TaskInfo;

public class IRemoteImpl extends Binder implements IRemote {

    public IRemoteImpl() {
        this.attachInterface(this,DESCRIPTOR);
    }

    public static IRemote asInterface(IBinder obj){
        if (obj == null) {
            return null;
        }
        if (obj instanceof IRemote){
            return (IRemote) obj;
        }
        return new Proxy(obj);
    }

    @Override
    protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
        //通过 code 对应的方法
        switch (code) {
            case TRANSACTION_add:
                //指定接口是 字符串DESCRIPTOR 所对应的
                data.enforceInterface(DESCRIPTOR);
                //接受到参数数据
                int num1 = data.readInt();
                int num2 = data.readInt();
                int result = this.add(num1, num2);
                reply.writeNoException();
                //把结果返回到返回参数中
                reply.writeInt(result);
                return true;
            case TRANSACTION_addTask:
                data.enforceInterface(DESCRIPTOR);
                TaskInfo info = null;
                if (data.readInt() != 0) {
                    //通过反序列化拿到数据
                    info = TaskInfo.CREATOR.createFromParcel(data);
                }
                TaskInfo resultInfo = this.addTask(info);
                reply.writeNoException();
                if ((resultInfo!=null)) {
                    reply.writeInt(1);
                    //数据写入到 parcel ，方便序列化
                    info.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                }
                else {
                    reply.writeInt(0);
                }
                return true;
            default:
                return super.onTransact(code, data, reply, flags);
        }
    }

    /**
     * 跨进程的代理类
     */

    private static class Proxy implements IRemote {
        private IBinder mRemote;

        Proxy(IBinder iBinder) {
            mRemote = iBinder;
        }

        public java.lang.String getInterfaceDescriptor() {
            return DESCRIPTOR;
        }

        @Override
        public IBinder asBinder() {
            return mRemote;
        }

        @Override
        public int add(int num1, int num2) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel replay = Parcel.obtain();

            int reslut;
            try {
                data.writeInterfaceToken(DESCRIPTOR);
                data.writeInt(num1);
                data.writeInt(num2);
                /**
                 * 可以看到，当跨进程被调用的时候，只是把调用方的参数，给自身的方法运行，然后再把结果返回回去
                 */
                mRemote.transact(TRANSACTION_add, data, replay, 0);
                replay.readException();
                reslut = replay.readInt();
            } finally {
                data.recycle();
                replay.recycle();
            }


            return reslut;
        }

        @Override
        public TaskInfo addTask(TaskInfo info) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel replay = Parcel.obtain();
            TaskInfo result;
            try {
                data.writeInterfaceToken(DESCRIPTOR);
                if ((info != null)) {
                    //用数据 0,1 ，来区分是否写入成功
                    data.writeInt(1);
                    info.writeToParcel(data, 0);
                } else {
                    data.writeInt(0);
                }
                mRemote.transact(TRANSACTION_addTask, data, replay, 0);

                replay.readException();
                if ((0 != replay.readInt())) {
                    result = TaskInfo.CREATOR.createFromParcel(replay);
                } else {
                    result = null;
                }
            } finally {
                data.recycle();
                replay.recycle();
            }
            return result;
        }

    }

    @Override
    public int add(int num1, int num2) throws RemoteException {
        return 0;
    }

    @Override
    public TaskInfo addTask(TaskInfo info) throws RemoteException {
        return null;
    }

    @Override
    public IBinder asBinder() {
        return this;
    }
}
